package com.example.hyznbk.view.fragment;

import android.support.v4.app.Fragment;
import android.util.Log;

import com.example.hyznbk.view.activity.MenuManagerActivity;
import com.trello.rxlifecycle.components.support.RxFragment;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by tangminglong on 17/9/19.
 */

public class MenuDelegatorFragment extends RxFragment {
    public static final String LTAG = MenuDelegatorFragment.class.getSimpleName();
    private boolean mHasMenu;
    private final Set<MenuDelegatorFragment> mChildrenShowingMenu = new HashSet<MenuDelegatorFragment>();
    private static final boolean DEBUG = false;

    private void debugLog(String what) {
        Log.v(LTAG, String.format("%s[%d] (%s): %s", mHasMenu ? "M" : "-", getId(), ((Object) this).getClass().getSimpleName(), what));
    }

    @Override
    public void setHasOptionsMenu(boolean hasMenu) {
        if (DEBUG) {
            debugLog(String.format("setHasOptionsMenu(%b)", hasMenu));
        }
        // Note that I'm not calling the super constructor here!
        // Cause I'll delegate the menu handling to the MenuManagerActivity instead of letting
        // the framework do it!
        mHasMenu = hasMenu;
        if (mHasMenu && isHierarchyVisible()) {
            showMenu();
        } else {
            hideMenu();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        boolean wasUserVisible = getUserVisibleHint();
        super.setUserVisibleHint(isVisibleToUser);
        if (wasUserVisible == isVisibleToUser) {
            return;
        }
        if (DEBUG) {
            debugLog(String.format("setUserVisibleHint(%b)", isVisibleToUser));
        }
        if (mHasMenu) {
            if (isVisibleToUser && isHierarchyVisible()) {
                showMenu();
            } else {
                hideMenu();
            }
        }
        if (isVisibleToUser) {
            notifyChildrenToShowMenu();
        } else {
            notifyChildrenToHideMenu();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (DEBUG) {
            debugLog("onPause()");
        }
        if (mHasMenu) {
            hideMenu();
        }
        notifyChildrenToHideMenu();
    }

    @Override
    public void onResume() {
        if (DEBUG) {
            debugLog("onResume()");
        }
        super.onResume();
        if (mHasMenu && isHierarchyVisible()) {
            showMenu();
        }
        notifyChildrenToShowMenu();
    }

    private boolean isHierarchyVisible() {
        boolean visible = getUserVisibleHint() && isResumed();
        Fragment parent = getParentFragment();
        boolean hierarchyVisible;
        if (parent == null) {
            hierarchyVisible = visible;
        } else if (parent instanceof MenuDelegatorFragment) {
            hierarchyVisible = visible && ((MenuDelegatorFragment) parent).isHierarchyVisible();
        } else {
            Log.w(LTAG, String.format("non-%s in the hierarchy, can't grant menu will work correctly in every situation: %s", LTAG, ((Object) parent).getClass().getSimpleName()));
            hierarchyVisible = visible && parent.getUserVisibleHint() && parent.isResumed();
        }
        if (DEBUG) {
            debugLog(String.format("isHierarchyVisible() -> %b", hierarchyVisible));
        }
        return hierarchyVisible;
    }

    private void showMenu() {
        if (((MenuManagerActivity) getActivity()).registerFragmentForOptionMenu(this)) {
            if (DEBUG) {
                debugLog("showMenu()");
            }
            if (getParentFragment() instanceof MenuDelegatorFragment) {
                ((MenuDelegatorFragment) getParentFragment()).addChildShowingMenu(this);
            }
        }
    }

    private void hideMenu() {
        if (((MenuManagerActivity) getActivity()).unregisterFragmentForOptionMenu(this)) {
            if (DEBUG) {
                debugLog("hideMenu()");
            }
            if (getParentFragment() instanceof MenuDelegatorFragment) {
                ((MenuDelegatorFragment) getParentFragment()).removeChildShowingMenu(this);
            }
        }
    }

    private void parentIsGoingAway() {
        if (DEBUG) {
            debugLog("parentIsGoingAway()");
        }
        hideMenu();
    }

    private void parentIsComingBack() {
        if (DEBUG) {
            debugLog("parentIsComingBack()");
        }
        if (mHasMenu && isHierarchyVisible()) {
            showMenu();
        }
    }

    private void removeChildShowingMenu(MenuDelegatorFragment child) {
        if (mChildrenShowingMenu.remove(child)) {
            if (DEBUG) {
                debugLog(String.format("removeChildShowingMenu([%s] %s)", child.getId(), ((Object) child).getClass().getSimpleName()));
            }
        }
    }

    private void addChildShowingMenu(MenuDelegatorFragment child) {
        if (mChildrenShowingMenu.add(child)) {
            if (DEBUG) {
                debugLog(String.format("addChildShowingMenu([%s] %s)", child.getId(), ((Object) child).getClass().getSimpleName()));
            }
        }
    }

    private void notifyChildrenToHideMenu() {
        if (mChildrenShowingMenu.size() == 0) {
            return;
        }
        if (DEBUG) {
            debugLog("notifyChildrenToHideMenu():" + mChildrenShowingMenu.size());
        }
        for (MenuDelegatorFragment child : mChildrenShowingMenu) {
            child.parentIsGoingAway();
        }
        mChildrenShowingMenu.clear();
    }

    private void notifyChildrenToShowMenu() {
        List<Fragment> children = getChildFragmentManager().getFragments();
        if (children == null || children.size() == 0) {
            return;
        }
        if (DEBUG) {
            debugLog("notifyChildrenToShowMenu():" + children.size());
        }
        for (Fragment child : children) {
            if (child instanceof MenuDelegatorFragment) {
                ((MenuDelegatorFragment) child).parentIsComingBack();
            } else if (child.hasOptionsMenu()) {
                Log.w(LTAG, String.format("non-%s in the hierarchy, can't grant menu will work correctly in every situation: %s", LTAG, ((Object) child).getClass().getSimpleName()));
            }
        }
    }
}
